Skip to content

input() asks in the console (P36) - #46

Merged
cedricvogel-leo merged 1 commit into
mainfrom
feature/console-input
Nov 2, 2026
Merged

cedricvogel-leo merged 1 commit into
mainfrom
feature/console-input

Conversation

@cedricvogel-leo

Copy link
Copy Markdown
Collaborator

input() now asks in the console instead of a dialog (P36), like a terminal or exam.net.

Behaviour

  • While a program (or a REPL input such as repl()) waits in input(prompt), the console's >>> line becomes the program's input line: the prompt in front, the cursor in it, accent border.

  • Enter sends the line. The prompt and the answer stay in the transcript as one line (> 2 * (3 + 4)), and the program's output follows. Afterwards the >>> line comes back.

  • Stop (and Ctrl+D in an empty line) ends the wait with EOFError: EOF when reading a line, as Python does. The program can catch it. Python is not restarted in that case, so the REPL keeps its namespace. Reset still restarts.

  • A recursive REPL of the learner's own works (checked up to 200 inputs deep).

  • «Tests» asks like ▶ (option (a)): the file runs first, as with Run.

  • Visualizer: it asks while it records the run, then shows the steps. The input(...) call is one step whose value is the typed text.

  • Without cross-origin isolation (the embed in LiaScript), input() raises RuntimeError: input() is not available here, with a new hint input-unavailable:

    • de: «input() funktioniert hier nicht: Diese Seite kann nicht auf eine Eingabe warten. In der IDE fragt die Konsole danach.»
    • en: "input() doesn't work here: this page can't wait for an answer. In the IDE, the console asks for it."

    Before, Pyodide's raw JsException text appeared there. The «In IDE öffnen» button is in the macro: glpython-liascript#29.

Decisions

  • The input line takes the place of the >>> line rather than a separate field inside the transcript:
    • Focus on the iPad: it is the same <input> element, so after typing repl() + return the focus (and, I expect, the iPad's software keyboard) stays. Moving focus to a new element without a tap usually doesn't bring the keyboard up in Safari; that is still to confirm on the iPad.
    • Placement: the line sits directly below the transcript and stays in view however long the transcript gets.
    • Shell look: the transcript gets the exchange as one line, as in a shell.
  • Prompt printed after the answer: Pyodide's stdout (batched) only passes whole lines on. So the bridge doesn't print the prompt before waiting; it prints prompt + answer as one line after Enter. Until that line arrives through the output stream, the console shows it already («answered lines»), so nothing flickers.
  • Output first: before the worker blocks, it sends the output it still holds back (the stream allows at most 50 messages per 50 ms), so everything printed before input() is visible.
  • The dialog stays only for a host that hides the console (no REPL and no emptyOutput, during a visualization without output). That never happens in the IDE, so in the IDE it's always the console.
  • While the program waits, nothing else starts: ▶ (it shows Stop anyway), «Tests», «Visualisieren», visualizing an example or a REPL entry, and host commands except Stop and Reset. The dialog was modal before; the input line isn't, and the worker is blocked.
  • The visualizer step was named _glpython_input(...), the bridge's internal name. That was already so; the function is now called input.

Checks

  • check-runtime-input.py (new, in test:runtime; the bridge under CPython, with a stub for Pyodide's js):

    • one input, an empty prompt and an empty answer, output before the prompt;
    • the recursive REPL (3 and 200 inputs);
    • Stop → EOFError (in a Run, in the REPL, caught by the program);
    • unavailable → RuntimeError with the hint;
    • the visualizer's single input(...) step;
    • the name input.
  • check-runtime-hints.py / check-error-hints.mjs: the new hint, de/en.

  • check-console-browser.mjs (test:console, Chrome + Pyodide). In a parent page with COOP/COEP:

    • ▶, then repl() typed in the REPL: three answers in the input line, prompt shown, focus in the line, no >>> line while waiting;
    • Stop → EOFError without restart, and Ctrl+D the same;
    • the visualizer asks, then shows the steps.

    Without isolation: the error and the hint, no dialog.

  • IDE: check-ide-browser.mjs has two new cases: ▶ with input("Name: ") and no dialog; a recursive REPL plus Stop → EOFError, after which the session still answers. They pass against this branch (packed and installed in the IDE locally), on IDE branch feature/console-input-check. Its PR follows with the bump once the tag exists.

  • Locally green: lint (the known warning), test:protocol, test:runtime, test:hints, build:embed + test:console.

How it goes live

  1. Embed: the merge to main deploys it to GitHub Pages. In LiaScript, input() then stops with the RuntimeError and the new hint (live within ~10 minutes, no course bump). Nothing else changes there.
  2. IDE: a tag on the merge commit (v0.1.22), then the IDE PR (bump + browser check). Only after that PR is merged and deployed does the IDE ask in the console.
  3. Macro (glpython-liascript#29): the «In IDE öffnen» button below a block with input(). Merging reaches courses only with a patch version bump of the course; without it they keep the old text («Python-input() ist in dieser LiaScript-Einbettung nicht verfügbar.»).

Manual tests

IDE (after the bump and deploy), Chrome on the desktop:

  1. ▶ with name = input("Name: ") / print("Hallo", name): the console asks with Name: in front of the line, cursor in it; Enter → Name: Zoë, Hallo Zoë; then >>> comes back.
  2. The P36 repl() program: ▶, then repl() in the REPL, three expressions, ende. The transcript reads like a shell.
  3. repl() again, then Stop while it waits: EOFError: EOF when reading a line, no «Python wurde neu gestartet», and berechnen("2 ** 10") still works.
  4. Ctrl+D in an empty input line: the same EOFError.
  5. «Visualisieren» on a program with input(): the console asks first, then the steps; input(...) is one step with the typed text.
  6. «Tests» on a file that calls input() at the top: asks first, then the report.
  7. While it waits: «Tests» and «Visualisieren» are disabled.

iPad (Safari, IDE):
8. Test 1 and test 2 with the software keyboard. Check three things:

  • after ▶ (a tap on a button), whether the keyboard comes up by itself or the line needs a tap;
  • after repl() + return, whether the keyboard stays and the next line can be typed right away;
  • whether return sends the line.
  1. Test 3 on the iPad: Stop while the keyboard is up.

LiaScript (after the embed deploy): a block with input() → ▶: RuntimeError: input() is not available here with the hint below it.

Follow-ups (not done here)

  • Partial line before input(): print("Zahl", end=": ") followed by input() only shows «Zahl: » after the answer, because Pyodide holds a line without its newline back. input("Zahl: ") is fine. Fixing it needs our own stdout handling instead of batched.
  • Doctest examples that call input() ask as well, but the doctest's Got then contains prompt + answer. CPython's doctest would have only the prompt and would read from stdin. Rare in the course.
  • Visualizing the REPL entry repl() shows the existing note (the replay can't answer input()). Replaying with the recorded answers would be possible.
  • Up/down in the input line doesn't recall earlier answers; in the >>> line it still recalls earlier inputs.

🤖 Generated with Claude Code

While a program waits in input(), the console's >>> line becomes its
input line with the prompt in front; prompt and answer stay in the
transcript as one line. Stop (or Ctrl+D) ends the wait with EOFError.
The dialog stays only for hosts that hide the console. Without
cross-origin isolation, input() raises RuntimeError with a hint that
points to the IDE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cedricvogel-leo
cedricvogel-leo merged commit 9b734fe into main Nov 2, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant